package com.gzsxy.sso.resources.config;

import com.gzsxy.sso.resources.exception.AuthExceptionEntryPoint;
import com.gzsxy.sso.resources.exception.CustomAccessDeniedHandler;
import com.gzsxy.sso.resources.handler.CustomLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;

/**
 * @author xiaolong
 * @version 1.0
 * @description: 资源Server端  WebSecurityConfig优先级高于ResourceServerConfig
 * @date 2021/11/11 20:25
 */
@Configuration
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {


    private static final String DEFAULT_RESOURCE_ID = "esjy_resource";

    /**
     * 授权失败且要求特定的内容类型相应 -没有权限
     */
    @Autowired
    CustomAccessDeniedHandler customAccessDeniedHandler;

    /**
     * 注销成功自定义处理
     */
    @Autowired
    CustomLogoutSuccessHandler logoutHandler;

    @Autowired
    private TokenStore tokenStore;



    //认证白名单
    private static String AUTH_WHITELIST = ""
            + "/swagger**/**,/**/v2/api-docs,/v2/api-docs/**,/swagger-ui.html,/resources/**,/configuration**/**,/doc.html,/valid**,"
            +"/oauth/**,/admin/user/**,/admin/role/**,/admin/menu/**,/admin/function/**,/admin/permission/**,/admin/userRole/**,/admin/app/**,/admin/file/**,/api/v1/config/menu/**,/api/v1/config/user/**,"
            +"/druid/**,"
            +"/webjars/**,/static/**,/lib/**,/**/*.js,/**/*.css,/favicon.ico,"
            +"/**/*.png,/**/*.jpg,/**/*.bmp,";


    /**
     *  授权
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        //设置创建session策略
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        //@formatter:off
        //所有请求必须授权
        http.authorizeRequests()
                //这些不需要认证就能访问
                .antMatchers(AUTH_WHITELIST.split("\\,")).permitAll()
                //客户端id资源作用域all
                .antMatchers("/**").access("#oauth2.hasScope('all')")
                .anyRequest().authenticated()  //其他请求需要认证才能请求
                .and().logout()
                //开启注销用户请求
                .logoutUrl("/oauth/logout")
                // 注销成功自定义处理
                .logoutSuccessHandler(logoutHandler)
                //防止网站攻击：get post --新版本已经融合了
                //关闭csrf功能,否则页面无法访问
                .and().csrf().disable();
        //@formatter:on
    }



    /**   资源安全配置相关
     *   resourceId: 用于分配给可授予的clientId
     *   stateless: 标记资源仅允许基于令牌的身份验证
     *   authenticationEntryPoint: 认证异常流程处理返回-token失效
     *   tokenExtractor: token提前方式
     *   accessDeniedHander:   授权失败且要求特定的内容类型相应 -没有权限
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        //资源id
        resources.resourceId(DEFAULT_RESOURCE_ID)
                //令牌存储模式   （基于redis存储的话就不需要验证令牌服务，因为redis中又相关用户数据）
                .tokenStore(tokenStore)
                //认证异常流程处理返回-token失效
                .authenticationEntryPoint(new AuthExceptionEntryPoint())
                //授权失败且要求特定的内容类型相应 -没有权限
                .accessDeniedHandler(customAccessDeniedHandler)
                .stateless(true);
    }
}
